
#include "lcd_internal.h"

#define LOG     LOG_INFO0
#define LOG1    LOG_INFO1
#define LOG3    LOG_INFO3

GUI_RAM_CODE
void lcd_write_completed(void)
{
    if( lcd_wrctl.block_write ) 
    {
        if( lcd_wrctl.offset < lcd_wrctl.size )
        {
            uint16_t remain = lcd_wrctl.size - lcd_wrctl.offset;
            if( remain > LCD_XFER_MAX_SIZE )
            {
                remain = LCD_XFER_MAX_SIZE;
            }
            LCD_SEND_DATA_ASYNC( lcd_wrctl.pdata + lcd_wrctl.offset, remain );
            lcd_wrctl.offset += remain;
        }
        else 
        {
            lcd_wrctl.blocks.used ++;
            if( lcd_wrctl.blocks.used < lcd_wrctl.blocks.count )
            {
                // check next row 
                lcd_wrctl.pdata += lcd_wrctl.blocks.offset; // next block  
                lcd_wrctl.offset = 0; 
                uint16_t remain = lcd_wrctl.size;
                if( remain > LCD_XFER_MAX_SIZE )
                {
                    remain = LCD_XFER_MAX_SIZE; 
                }
                
                LCD_SEND_DATA_ASYNC( lcd_wrctl.pdata, remain );
                lcd_wrctl.offset = remain; //start a block 
            }
            else 
            {
                lcd_wrctl.isbusy = false; 
            }
        }
    }
    else 
    {
        if( lcd_wrctl.offset < lcd_wrctl.size )
        {
            uint16_t remain = lcd_wrctl.size - lcd_wrctl.offset;
            if( remain > LCD_XFER_MAX_SIZE )
            {
                remain = LCD_XFER_MAX_SIZE;
            }
            LCD_SEND_DATA_ASYNC( lcd_wrctl.pdata + lcd_wrctl.offset, remain );
            lcd_wrctl.offset += remain;
        }
        else 
        {
            lcd_wrctl.isbusy = false; 
        }
    }
}

static void driver_init(void)
{
    LCD_SET_RESET;
    LCD_DELAY_MS(100);
    LCD_SET_nRESET;
    LCD_DELAY_MS( 100 );
    
     
    lcd_write_command( 0xEF ); 
    lcd_write_command( 0xEB ); 
    {
        uint8_t data[] = {0x14}; 
        lcd_write_data( data, sizeof(data) );
    }

    lcd_write_command( 0xFE );
    lcd_write_command( 0xEF );
    
    lcd_write_command( 0xEB ); 
    {
        uint8_t data[] = {0x14}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x84 ); 
    {
        uint8_t data[] = {0x40}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x85 ); 
    {
        uint8_t data[] = {0xff}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x86 ); 
    {
        uint8_t data[] = {0xff}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x87 ); 
    {
        uint8_t data[] = {0xff}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x88 ); 
    {
        uint8_t data[] = {0x0A}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x89 ); 
    {
        uint8_t data[] = {0x21}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x8A ); 
    {
        uint8_t data[] = {0x00}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x8B ); 
    {
        uint8_t data[] = {0x80}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x8C ); 
    {
        uint8_t data[] = {0x01}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x8D ); 
    {
        uint8_t data[] = {0x01}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x8E ); 
    {
        uint8_t data[] = {0xFF}; 
        lcd_write_data( data, sizeof(data) );
    }

    lcd_write_command( 0x8F ); 
    {
        uint8_t data[] = {0xFF}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    
    lcd_write_command( 0xB6 );
    {
        uint8_t data[] = {0x00, 0x20 }; 
        lcd_write_data( data, sizeof(data) );
    }

    lcd_write_command( 0x36 );
    {
        uint8_t data[] = {0x08}; 
        lcd_write_data( data, sizeof(data) );
    }
    lcd_write_command( 0x3A );
    {
        uint8_t data[] = {0x05};
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x90 );
    {
        uint8_t data[] = {0x08, 0x08, 0x08, 0x08}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xBD );
    {
        uint8_t data[] = {0x06}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xBC );
    {
        uint8_t data[] = {0x00 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xFF );
    {
        uint8_t data[] = {0x60, 0x01, 0x04}; 
        lcd_write_data( data, sizeof(data) );
    }    
    
    lcd_write_command( 0xC3 );
    {
        uint8_t data[] = {0x13};  
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xC4 );
    {
        uint8_t data[] = {0x13 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xC9 );
    {
        uint8_t data[] = {0x22 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xBE );
    {
        uint8_t data[] = {0x11 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xE1 );
    {
        uint8_t data[] = {0x10, 0x0E }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xDF );
    {
        uint8_t data[] = { 0x21, 0x0c, 0x02 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xF0 );
    {
        uint8_t data[] = {0x45, 0x09, 0x08, 0x08, 0x26, 0x2A }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xF1 );
    {
        uint8_t data[] = {0x43, 0x70, 0x72, 0x36, 0x37, 0x6F }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xF2 );
    {
        uint8_t data[] = { 0x45, 0x09, 0x08, 0x08, 0x26, 0x2A }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xF3 );
    {
        uint8_t data[] = {0x43, 0x70, 0x72, 0x36, 0x37, 0x6F }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xED );
    {
        uint8_t data[] = {0x1B, 0x0B }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xAE );
    {
        uint8_t data[] = {0x77 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xCD );
    {
        uint8_t data[] = {0x63 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x70 );
    {
        uint8_t data[] = {0x07, 0x07, 0x04, 0x0E, 0x0F, 0x09, 0x07, 0x08, 0x03 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xE8 );
    {
        uint8_t data[] = {0x34 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x62 );
    {
        uint8_t data[] = {0x18, 0x0D, 0x71, 0xED, 0x70, 0x70, 0x18, 0x0F, 0x71, 0xEF, 0x70, 0x70 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x63 );
    {
        uint8_t data[] = {0x18, 0x11, 0x71, 0xF1, 0x70, 0x70, 0x18, 0x13, 0x71, 0xF3, 0x70, 0x70 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x64 );
    {
        uint8_t data[] = {0x28, 0x29, 0xF1, 0x01, 0xF1, 0x00, 0x07 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x66 );
    {
        uint8_t data[] = {0x3C, 0x00, 0xCD, 0x67, 0x45, 0x45, 0x10, 0x00, 0x00, 0x00 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x67 );
    {
        uint8_t data[] = {0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x54, 0x10, 0x32, 0x98 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x74 );
    {
        uint8_t data[] = {0x10, 0x85, 0x80, 0x00, 0x00, 0x4E, 0x00 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x98 );
    {
        uint8_t data[] = {0x3e, 0x07 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x35 );
    lcd_write_command( 0x21 );
    
    platform_delay_ms( 120 ); 

#if 0
    lcd_write_command( 0x28 ); // turn off 
    lcd_write_command( 0x10 ); // sleep in 
#else 
    lcd_write_command( 0x11 );
    lcd_write_command( 0x29 );  // display ON 
//    platform_delay_ms( 20 ); 
#endif 
}

void em_lcd_init(void)
{
    lcd_common_init();
    lcd_config_gpio();
    driver_init();
}

void em_lcd_power_off(void)
{
    lcd_write_command( 0x28 ); // turn off 
    lcd_write_command( 0x10 ); // sleep in 
}
void em_lcd_power_on(void)
{
    lcd_gdma_init(); 
    
    lcd_write_command( 0x11 ); // sleep out 
    lcd_write_command( 0x29 ); // turn on   
}
void em_lcd_sleep_out(void)
{
    lcd_write_command( 0x11 ); 
}

void em_lcd_turn_on(void)
{
    lcd_write_command( 0x29 );
}

DATA_RAM_FUNCTION
void em_lcd_set_window(int16_t x0, int16_t y0, int16_t w, int16_t h)
{
    uint16_t xstart = x0;
    uint16_t ystart = y0;
    uint16_t xend = x0 + w - 1;
    uint16_t yend = y0 + h - 1;
    
    // column address set
    lcd_write_command(0x2A); { // CASET
        uint8_t data[] = { (xstart >> 8) & 0xFF , xstart & 0xFF, (xend >> 8) & 0xFF, xend & 0xFF };
        lcd_write_data(data, sizeof(data));
    }
    // row address set
    lcd_write_command(0x2B); {// RASET
        uint8_t data[] = { (ystart >> 8) & 0xFF, ystart & 0xFF, (yend >> 8) & 0xFF, yend & 0xFF };
        lcd_write_data(data, sizeof(data));
    }
    // write to RAM
    lcd_write_command(0x2C); // RAMWR    
}
GUI_RAM_CODE
void em_lcd_write(uint8_t* p_buffer, uint32_t size)
{   
    if( lcd_wrctl.isbusy )
    {
        return;
    }
    
    lcd_wrctl.isbusy = true; 
    lcd_wrctl.block_write = false;
    lcd_wrctl.pdata = (uint8_t*)p_buffer;
    lcd_wrctl.offset = 0;
    lcd_wrctl.size = size;
    
    uint32_t chunk_remain = size; 
    if( chunk_remain > LCD_XFER_MAX_SIZE )
    {
        chunk_remain = LCD_XFER_MAX_SIZE; 
    }
    lcd_wrctl.offset = chunk_remain;
    LCD_SEND_DATA_ASYNC( lcd_wrctl.pdata, chunk_remain );
}

/*
    p_buffer -> LCD Memory 
    offset   -> next block offset 
    size     -> size of block  
    rows     -> block count 
*/
GUI_RAM_CODE
void em_lcd_write_block( uint8_t* p_buffer, int16_t offset, uint16_t size, int16_t count )
{
    if( lcd_wrctl.isbusy )
    {
        return;
    }
    
    lcd_wrctl.isbusy                = true;
    lcd_wrctl.block_write           = true; 
    lcd_wrctl.pdata                 = (uint8_t*)p_buffer;
    lcd_wrctl.offset                = 0; 
    lcd_wrctl.size                  = size; 
    
    lcd_wrctl.blocks.used           = 0;
    lcd_wrctl.blocks.size           = size;
    lcd_wrctl.blocks.count          = count;
    lcd_wrctl.blocks.offset         = offset;
    
   uint32_t chunk_remain = size; 
   if( chunk_remain > LCD_XFER_MAX_SIZE )
   {
       chunk_remain = LCD_XFER_MAX_SIZE; 
   }
    lcd_wrctl.offset                = chunk_remain; 
    LCD_SEND_DATA_ASYNC( lcd_wrctl.pdata, chunk_remain );
}

void em_lcd_wait_transfer_completed(void)
{
    while( lcd_wrctl.isbusy );
}

bool em_lcd_check_transfer_completed(void)
{
    return lcd_wrctl.isbusy; 
}

// void iqw_module_lcd_send_data( uint8_t * data, uint32_t len)
// {
//     SPI_SendBuffer( LCD_SPI_BUS, data, len ); 
// }

// void iqw_module_lcd_draw_point(uint16_t x0, uint16_t y0, uint16_t color)
// {
//     iqw_module_lcd_set_address_window(x0, y0, x0 + 1, y0 + 1 );
//     SPI_SendBuffer( LCD_SPI_BUS, (uint8_t*)&color, 2 ); 
// }

// void iqw_module_lcd_draw_rect(uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t color)
// {
// 	uint8_t i,j;
//     iqw_module_lcd_set_address_window(x0, y0, x0 + w, y0 + h );
// 	for(i=0;i<w;i++)
// 		for(j=0;j<h;j++)
//     SPI_SendBuffer( LCD_SPI_BUS, (uint8_t*)&color, 2 ); 
// }








// void iqw_module_lcd_init_for_charging(void)
// {
//     driver_init();
    
//     m_lcd_write.state = fsmLCDIsInited; 
// }

